package sorted;

import ordered.Cursor;
import ordered.DoubleLinkedList;
import ordered.OrderedListAsDoubleLinkedList;
import iterator.Iterator;
import visitor.Visitor;
import wrapper.Comparable;
import container.AbstractSearchableContainer;
import container.ContainerEmptyException;
import enumeration.Enumeration;

public class SortedListAsDoubleLinkedList extends OrderedListAsDoubleLinkedList
		implements SortedList {
	private DoubleLinkedList doubleLinkedList;

	public SortedListAsDoubleLinkedList() {
		doubleLinkedList = new DoubleLinkedList();
	}

	public void insert(Comparable arg) {
		DoubleLinkedList.Element ptr;
		for (ptr = doubleLinkedList.getHead(); ptr != null; ptr = ptr.getNext()) {
			Comparable object = (Comparable) ptr.getDatum();
			if (object.isGE(arg))
				break;
		}
		if (ptr == null)
			doubleLinkedList.append(arg);
		else
			ptr.insertBefore(arg);
		++count;
	}

	public Comparable get(int offset) {
		if (offset < 0 || offset >= count)
			throw new IndexOutOfBoundsException();

		DoubleLinkedList.Element ptr = doubleLinkedList.getHead();
		for (int i = 0; i < offset && ptr != null; ++i)
			ptr = ptr.getNext();
		return (Comparable) ptr.getDatum();
	}

	public boolean isMember(Comparable object) {
		for (DoubleLinkedList.Element ptr = doubleLinkedList.getHead(); ptr != null; ptr = ptr
				.getNext()) {
			if (((Comparable) ptr.getDatum()).isEQ(object))
				return true;
		}
		return false;
	}

	public Comparable find(Comparable arg) {
		for (DoubleLinkedList.Element ptr = doubleLinkedList.getHead(); ptr != null; ptr = ptr
				.getNext()) {
			Comparable object = (Comparable) ptr.getDatum();
			if (object.isEQ(arg))
				return object;
		}
		return null;
	}

	public void withdraw(Comparable object) {
		if (count == 0)
			try {
				throw new ContainerEmptyException();
			} catch (ContainerEmptyException e) {
				System.out.println("A lista está vazia!");
			}
		doubleLinkedList.extract(object);
		--count;
	}

	protected class MyCursor implements Cursor {
		DoubleLinkedList.Element element;

		MyCursor(DoubleLinkedList.Element element) {
			this.element = element;
		}

		public Comparable getDatum() {
			return (Comparable) element.getDatum();
		}

		public void insertAfter(Comparable object) {
			try {
				throw new InvalidOperationException("Operação Inválida");
			} catch (InvalidOperationException e) {
				e.printStackTrace();
			}
		}

		public void withdraw() {
			doubleLinkedList.extract(element.getDatum());
			--count;
		}

		public void insertBefore(Comparable object) {
			try {
				throw new InvalidOperationException("Operação Inválida");
			} catch (InvalidOperationException e) {
				e.printStackTrace();
			}
		}
	}

	public Cursor findPosition(Comparable arg) {
		DoubleLinkedList.Element ptr;
		for (ptr = doubleLinkedList.getHead(); ptr != null; ptr = ptr.getNext()) {
			Comparable object = (Comparable) ptr.getDatum();
			if (object.isEQ(arg))
				break;
		}
		return new MyCursor(ptr);
	}

	@Override
	protected int compareTo(Comparable arg) {
		SortedListAsDoubleLinkedList sortedList = (SortedListAsDoubleLinkedList) arg;
		if(this.getCount() < sortedList.getCount())
			return -1;
		else if(this.getCount() > sortedList.getCount())
			return +1;
		else return 0;
	}

	@Override
	public void accept(Visitor visitor) {
		doubleLinkedList.accept(visitor);
	}

	@Override
	public Enumeration getEnumeration() {
		return doubleLinkedList.getEnumeration();
	}

	@Override
	public Iterator getIterator() {
		return doubleLinkedList.getIterator();
	}


	@Override
	public void purge() {
		doubleLinkedList.purge();
	}
}